use rocket::{
  delete, get,
  http::Status,
  post, put,
  response::status::{Custom, NoContent},
  serde::json::{serde_json::json, Json, Value},
};

use crate::{
  db::DbConn,
  error::server_error,
  mappers::user::UserMapper,
  models::user::{NewUser, UpdateUser},
};

#[get("/user")]
pub async fn get_user(db: DbConn) -> Result<Value, Custom<Value>> {
  db.run(|conn| {
    UserMapper::find_multiple(conn, 100)
      .map(|result| json!(result))
      .map_err(|err| server_error(&err))
  })
  .await
}

#[get("/user/<id>")]
pub async fn view_user(db: DbConn, id: i32) -> Result<Value, Custom<Value>> {
  db.run(move |conn| {
    UserMapper::find(conn, id)
      .map(|result| json!(result))
      .map_err(|err| server_error(&err))
  })
  .await
}

#[post("/user", format = "json", data = "<new_user>")]
pub async fn create_user(
  db: DbConn,
  new_user: Json<NewUser>,
) -> Result<Custom<Value>, Custom<Value>> {
  db.run(|conn| {
    UserMapper::create(conn, new_user.into_inner())
      .map(|result| Custom(Status::Created, json!(result)))
      .map_err(|err| server_error(&err))
  })
  .await
}

#[put("/user/<id>", format = "json", data = "<update_user>")]
pub async fn update_user(
  db: DbConn,
  id: i32,
  update_user: Json<UpdateUser>,
) -> Result<Value, Custom<Value>> {
  db.run(move |conn| {
    UserMapper::update(conn, id, update_user.into_inner())
      .map(|result| json!(result))
      .map_err(|err| server_error(&err))
  })
  .await
}

#[delete("/user/<id>")]
pub async fn delete_user(
  db: DbConn,
  id: i32,
) -> Result<NoContent, Custom<Value>> {
  db.run(move |conn| {
    UserMapper::delete(conn, id)
      .map(|_| NoContent)
      .map_err(|err| server_error(&err))
  })
  .await
}
